package com.ctg.polling.web;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.TypedQuery;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.ctg.polling.domain.Choice;
import com.ctg.polling.domain.JPollingUser;
import com.ctg.polling.domain.Poll;
import com.ctg.polling.domain.UserPoll;
import com.ctg.polling.domain.UserSelection;
import com.ctg.polling.web.dataobject.PollResultDO;
import com.ctg.polling.web.dataobject.PollResultsDO;

@RequestMapping("/userpolls")
@Controller
public class UserPollsController {

	Logger logger = Logger.getLogger(UserPollsController.class);

	/**
	 * See AOP code from other controllers for more information.
	 * @param page
	 * @param size
	 * @param request
	 * @param model
	 * @return displayed page.
	 */
    @RequestMapping(method=RequestMethod.GET)
    public String list(@RequestParam(value="page", required = false) Integer page, @RequestParam(value="size", required = false) Integer size, HttpServletRequest request, Model uiModel) {
    	
    	List<Poll> polls = null;
    	
    	if (page != null || size != null) {
    		int sizeNo = size == null ? 10 : size.intValue();
    		polls = Poll.findPollEntries(page == null ? 0 : (page.intValue() - 1) * sizeNo, sizeNo);
    		uiModel.addAttribute("polls", polls);
    		float nrOfPages = (float) Poll.countPolls() / sizeNo;
            uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));
    	} else {
    		polls = Poll.findAllPolls();
    		uiModel.addAttribute("polls", polls);
    	}

    	
    	// populate 'isAlreadyAnswered' property on Poll instance.
    	Principal principal = request.getUserPrincipal();
    	if (principal != null && polls != null) {
    		
        	// make a copy a polls list. 
        	// this new list will be set up to contain only answered polls.
    		List<Poll> pollsAnswered = new ArrayList<Poll>(polls);

    		String login = principal.getName();
    		JPollingUser polled = JPollingUser.findJPollingUsersByUsername(login).getSingleResult();
    		
    		// we've got here all the polls which are already answered by the current user.
    		List<UserSelection> userSelections = UserSelection.findUserSelectionsByPolled(polled).getResultList();
    		HashSet<Poll> answeredPolls = new HashSet<Poll>();
    		for (UserSelection userSelection : userSelections) {
    			answeredPolls.add(userSelection.getChoice().getPoll());
    		}
    		
    		pollsAnswered.retainAll(answeredPolls);
    		
    		// mark the current polls which are already answered by the current user.
			for (Poll poll : pollsAnswered) {
				poll.setAlreadyAnswered(true);
			}
    		
       	}
    	
    	return "userpolls/list";
    }
        
    /**
     * View results.
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String show(@PathVariable("id") Long id, Model uiModel, HttpServletRequest request) {
    	// fetch poll object.
    	Poll poll = Poll.findPoll(id);
    	List<Choice> choices = Choice.findChoicesByPoll(poll).getResultList();
    	PollResultsDO results = new PollResultsDO();
    	for (Choice choice : choices) {
    		// fetch results
        	TypedQuery<UserSelection> userSelections = UserSelection.findUserSelectionsByChoice(choice);
        	PollResultDO pollResultDO = new PollResultDO(choice.getLabel(), userSelections.getResultList().size());
        	results.addEntry(pollResultDO);
    	}
    	// calculate results.
    	results.populatePercentFields();
    	
    	// put the object in the model
    	uiModel.addAttribute("poll", poll);
    	uiModel.addAttribute("choices", results.getResultsSortedList());
    	uiModel.addAttribute("choices_count", Choice.countChoices());
    	
        return "userpolls/results";
    }
    
    /**
     * initialise form.
     * @param id
     * @param uiModel
     * @return
     */
    @RequestMapping(value = "/{id}", params = "form", method = RequestMethod.GET)
    public String updateForm(@PathVariable("id") Long id, Model uiModel) {
    	// fetch poll object.
    	Poll poll = Poll.findPoll(id);
    	List<Choice> choices = Choice.findChoicesByPoll(poll).getResultList();
    	UserPoll userpoll = new UserPoll();
    	userpoll.setPoll(poll);

    	// put the object in the model
    	uiModel.addAttribute("poll", poll);
    	uiModel.addAttribute("choices", choices);
    	uiModel.addAttribute("choices_count", Choice.countChoices());
    	uiModel.addAttribute("userpoll", userpoll);
    	
    	return "userpolls/fillin";
    }
    /**
     * fetch form parameters.
     * @param userPoll
     * @param bindingResult
     * @param uiModel
     * @param httpServletRequest
     * @return
     */
    @RequestMapping(method = RequestMethod.POST)
    public String create(@Valid UserPoll userPoll, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            uiModel.addAttribute("userpoll", userPoll);
            return "userpolls/fillin";
        }
        if (httpServletRequest.getUserPrincipal() == null) {
            uiModel.addAttribute("userpoll", userPoll);
            // TODO : return an exception
            return "userpolls/fillin";
        }
        // TODO ...
        // if user has already answered this question, then an error is thrown and navigation forwarded to results list.
        /*if () {
        	
        }*/

        // TODO : what is this line doing ?
        uiModel.asMap().clear();
        
        // TODO : fetch 0 or *
        // Choice choice = Choice.findChoice(userPoll.getChoices().get(0).getId());
        if (userPoll.getChoices() != null) {
	        for (Choice choice : userPoll.getChoices()) {
	        	UserSelection userSelection = new UserSelection();
	        	String login = httpServletRequest.getUserPrincipal().getName();
	            JPollingUser pollingUser = JPollingUser.findJPollingUsersByUsername(login).getSingleResult();
	            userSelection.setChoice(choice);
	            userSelection.setPolled(pollingUser);
	            userSelection.setSelectionDate(new Date());
	            userSelection.persist();   
	        }
        }
        
        return "redirect:/userpolls/" + userPoll.getPoll().getId().toString();
    }
}